package edu.faytechcc.csc.business;

import java.io.File;
import java.util.ArrayList;
import java.util.Scanner;

/**
 * This class contains all of the information needed to edit Alice Class files. 
 * It holds the student names, Alice classes to be edited, the section number,
 * and the destination as to where the converted classes go. 
 * 
 * @author Charles Bryan
 */
public class Model
{

    private String studentFile;
    private ArrayList<String> students;
    private ArrayList<String> aliceClasses;
    private String section;
    private String destination;
    private String directory = "";

    public Model()
    {
        //not sure why this is needed but hmmmm......it is.
    }

    /**
     * Adds a single student into the list of students, i.e. creates a list of 
     * one. Note this method will overwrite any previously added students.
     * 
     * @param student the student to set
     * @throws Exception if the student name is not valid 
     */
    public void setStudent(String student) throws Exception
    {
        if (!isValidStudentName(student))
        {
            throw new Exception("Student name is not in the correct format.");
        }
        students = new ArrayList<String>();
        students.add(student);
    }

    /**
     * Reads through the file of student names and adds each to the list of
     * students. Note this method will overwrite any previously added
     * students.
     * 
     * @param studentFile the FULL path of the file of students to be added
     * @throws Exception if the file does not exist or if it is not in the 
     * correct format
     */
    public void setStudentFile(String studentFile) throws Exception
    {
        this.studentFile = studentFile;
        students = new ArrayList<String>();
        Scanner inFile = new Scanner(new File(this.studentFile));
        String line;
        while (inFile.hasNext())
        {
            line = inFile.nextLine();
            if (!isValidStudentName(line))
            {
                throw new Exception("File not in the correct format.");
            }
            students.add(line);
        }
    }

    /**
     * Adds a single Alice Class to the list of Alice classes. i.e. creates a 
     * list of one. Note this method will overwrite any previously added 
     * classes.
     * 
     * @param aliceClass the aliceClass to set
     * @throws Exception  If the Alice class file does not exists.
     */
    public void setAliceClass(String aliceClass) throws Exception
    {
        if (!new File(aliceClass).exists())
        {
            throw new Exception("Alice Class does not exist.\n" + aliceClass);
        }
        aliceClasses = new ArrayList<String>();
        aliceClasses.add(aliceClass);
    }
    
    /**
     * Adds all of the Alice classes found in the input directory aliceClassDir
     * into the list of Alice classes. Note this method will overwrite any 
     * previously added classes. This method may include all of the classes
     * in subdirectories and/or keep the subdirectory structure based on the 
     * input.
     * 
     * @param aliceClassDir the FULL path of the directory of Alice Classes
     * @param includeSubs true if the Alice classes in all of the subdirectories 
     * are to be added, false if not.
     * @param keepDirStructure true if the subdirectory structure is to be kept,
     * false otherwise.
     * @throws Exception If no Alice classes were found in the directory.
     */
    public void setAliceClassDirectory(String aliceClassDir, 
            boolean includeSubs, boolean keepDirStructure)
            throws Exception
    {
        aliceClasses = new ArrayList<String>();
        if(keepDirStructure)
        {
            this.directory = aliceClassDir;
        }
        addClassFromDir(new File(aliceClassDir), includeSubs);
        if(aliceClasses.isEmpty())
        {
            throw new Exception("No Alice classes found.");
        }
        
    }
    
    /**
     * Recursive helper to add classes from the directory structure. If 
     * includeSubs is false, no recursive calls are made.
     * 
     * @param dir the directory the Alice class files are to be added from.
     * @param includeSubs true if the Alice classes in all of the subdirectories 
     * are to be added, false if not. 
     */
    private void addClassFromDir(File dir, boolean includeSubs)
    {
        //get a list of "files" in the directory
        File[] files = dir.listFiles();
        
        for(File f : files)
        {
            if (f.isDirectory() && includeSubs) 
            {
                //recursive call into dir as needed
                addClassFromDir(f, includeSubs);
            }
            else if (f.getName().endsWith(".a2c")) //skip non-Alice class files
            {
                aliceClasses.add(f.getPath());
            }
        }
    }

    /**
     * Adds all of the Alice classes found in the file aliceClassFile
     * into the list of Alice classes. Note this method will overwrite any 
     * previously added classes.
     * 
     * @param aliceClassFile The FULL path of a file with a list of FULL path
     * Alice class file locations
     * @throws Exception  If the file isn't found or if the Classes in it do 
     * not exists in the given location
     */
    public void setAliceClassFile(String aliceClassFile) throws Exception
    {
        aliceClasses = new ArrayList<String>();
        Scanner inFile = new Scanner(new File(aliceClassFile));
        
        String line;
        while (inFile.hasNext())
        {
            line = inFile.nextLine();
            if (!new File(line).exists())
            {
                //opps, not an alice class file...
                throw new Exception("Alice Class does not exist.\n" + line);
            }
            if(! isValidAliceClassName(line))
            {
                throw new Exception("Oppps, not a valid Alice class file." +
                        "\n" + line);
            }
            aliceClasses.add(line);
        }
    }

    /**
     * Allows access to the list of Students
     * 
     * @return the list of students names
     */
    public ArrayList<String> getStudents()
    {
        return students;
    }

    /**
     * Allows access to the Alice Classes
     * 
     * @return the list of aliceClasses
     */
    public ArrayList<String> getAliceClasses()
    {
        return aliceClasses;
    }

    /**
     * Allows Access to the section number
     * @return the section
     */
    public String getSection()
    {
        return section;
    }

    /**
     * Sets the section number
     * @param section the section to set
     */
    public void setSection(String section)
    {
        this.section = section;
    }

    /**
     * Returns the string that holds the destination directory for the 
     * finalized zip files
     * 
     * @return the destination
     */
    public String getDestination()
    {
        return destination;
    }

    /**
     * Sets the FULL path of the destination for the finalized zip files to go. 
     * @param destination the destination to set
     * @throws Exception  
     */
    public void setDestination(String destination) throws Exception
    {
        File dir = new File(destination);
        if(!dir.isDirectory())
        {
            throw new Exception("This is not a valid directory: "
                    + "\n\t" + destination);
        }
        if(!(dir.canRead() && dir.canWrite()))
        {
            throw new Exception("The permissions in this directory do not "
                    + "allow read and/or write acces: \n\t" + destination);
        }
        this.destination = destination;
    }

    /**
     * Allows access to the local directory for the Alice files, this is used
     * to keep, or not, keep the directory structure when working with the 
     * full directory and subdirectory conversion.
     * 
     * @return the directory
     */
    public String getDirectory()
    {
        return directory;
    }
    
    /**
     * A helper that checks to see if a string only contains letters and numbers
     * @param name The string being checked
     * @return true if name contains only letters and/or digits, false otherwise
     */
    private boolean isValidStudentName(String name)
    {
        boolean result = true;

        for (int index = 0; index < name.length() && result; index++)
        {
            result = Character.isLetterOrDigit(name.charAt(index));
        }
        return result;
    }

    /**
     * A helper that looks to see if a string ends in *.a2c, therefore making 
     * it an Alice Class file
     * @param name The string being checked
     * @return true if the string ends with *.a2c, false otherwise
     */
    private boolean isValidAliceClassName(String name)
    {
        return name.endsWith(".a2c");
    }    
}
